list box: Make focusable headers possible
authorMatthias Clasen <mclasen@redhat.com>
Sat, 22 Aug 2015 00:51:03 +0000 (20:51 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 22 Aug 2015 00:51:03 +0000 (20:51 -0400)
Previously we were assuming that only list box rows could occur
as focus children of a list box, and would crash if that wasn't
the case. This commit handles this case, and integrates focusable
headers into directional keynav and the focus chain.

The typical case of using separators as headers is not affected
by this change.

https://bugzilla.gnome.org/show_bug.cgi?id=753694

gtk/gtklistbox.c

index c278326b86fbf4b6a943bc0bac3a8eab0d0ece1c..0e8f9c0b3a67c7e7d96d15efcaa78155083d6382 100644 (file)
@@ -1939,8 +1939,11 @@ gtk_list_box_focus (GtkWidget        *widget,
   GtkListBoxPrivate *priv = BOX_PRIV (box);
   GtkWidget *focus_child;
   GtkListBoxRow *next_focus_row;
+  GtkWidget *row;
+  GtkWidget *header;
 
   focus_child = gtk_container_get_focus_child ((GtkContainer *)box);
+
   next_focus_row = NULL;
   if (focus_child != NULL)
     {
@@ -1951,7 +1954,23 @@ gtk_list_box_focus (GtkWidget        *widget,
 
       if (direction == GTK_DIR_UP || direction == GTK_DIR_TAB_BACKWARD)
         {
-          i = gtk_list_box_get_previous_visible (box, ROW_PRIV (GTK_LIST_BOX_ROW (focus_child))->iter);
+          if (GTK_IS_LIST_BOX_ROW (focus_child))
+            {
+              header = ROW_PRIV (GTK_LIST_BOX_ROW (focus_child))->header;
+              if (header && gtk_widget_child_focus (header, direction))
+                return TRUE;
+            }
+
+          if (GTK_IS_LIST_BOX_ROW (focus_child))
+            row = focus_child;
+          else
+            row = g_hash_table_lookup (priv->header_hash, focus_child);
+
+          if (GTK_IS_LIST_BOX_ROW (row))
+            i = gtk_list_box_get_previous_visible (box, ROW_PRIV (GTK_LIST_BOX_ROW (row))->iter);
+          else
+            i = NULL;
+
           while (i != NULL)
             {
               if (gtk_widget_get_sensitive (g_sequence_get (i)))
@@ -1965,7 +1984,17 @@ gtk_list_box_focus (GtkWidget        *widget,
         }
       else if (direction == GTK_DIR_DOWN || direction == GTK_DIR_TAB_FORWARD)
         {
-          i = gtk_list_box_get_next_visible (box, ROW_PRIV (GTK_LIST_BOX_ROW (focus_child))->iter);
+          if (GTK_IS_LIST_BOX_ROW (focus_child))
+            i = gtk_list_box_get_next_visible (box, ROW_PRIV (GTK_LIST_BOX_ROW (focus_child))->iter);
+          else
+            {
+              row = g_hash_table_lookup (priv->header_hash, focus_child);
+              if (GTK_IS_LIST_BOX_ROW (row))
+                i = ROW_PRIV (GTK_LIST_BOX_ROW (row))->iter;
+              else
+                i = NULL;
+            }
+
           while (!g_sequence_iter_is_end (i))
             {
               if (gtk_widget_get_sensitive (g_sequence_get (i)))
@@ -2008,10 +2037,17 @@ gtk_list_box_focus (GtkWidget        *widget,
       return FALSE;
     }
 
+  if (direction == GTK_DIR_DOWN || direction == GTK_DIR_TAB_FORWARD)
+    {
+      header = ROW_PRIV (next_focus_row)->header;
+      if (header && gtk_widget_child_focus (header, direction))
+        return TRUE;
+    }
+
   if (gtk_widget_child_focus (GTK_WIDGET (next_focus_row), direction))
     return TRUE;
 
-  return TRUE;
+  return FALSE;
 }
 
 static gboolean